'''
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with self work for additional information
 * regarding copyright ownership.  The ASF licenses self file
 * to you under the Apache License, Version 2.0 (the
 * "License") you may not use self file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http:#www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
'''
from base.enhanced.EnhNode import EnhNode
from base.exception.PropertyNotFoundException import PropertyNotFoundException
from base.graph.NodeFactory import NodeFactory
from base.rdf.AnonId import AnonId
from base.rdf.HasNoModelException import HasNoModelException
from base.rdf.LiteralRequiredException import LiteralRequiredException
from base.rdf.Resource import Resource

# import org.apache.jena.datatypes.RDFDatatype;
# import org.apache.jena.enhanced.EnhGraph;
# import org.apache.jena.enhanced.EnhNode;
# import org.apache.jena.enhanced.Implementation;
# import org.apache.jena.graph.Node;
# import org.apache.jena.graph.NodeFactory;
# import org.apache.jena.graph.Triple;
# import org.apache.jena.rdf.model.*;
# import org.apache.jena.shared.PropertyNotFoundException;

'''
 * An implementation of Resource.
'''


class ResourceImpl(EnhNode, Resource):
    # param
    # result Implementation factory = new
    # def Implementation factory = Implementation(self):
    #     # @Override
    # # param Node n, EnhGraph eg
    # # result boolean
    # def canWrap(self, n, eg):
    #         return not n.isLiteral()
    #
    #
    #     # @Override
    # # param Node n, EnhGraph eg
    # # result EnhNode
    # def wrap(self, n, eg):
    #         if (n.isLiteral()):
    #     raise ResourceRequiredException(n)
    #         return ResourceImpl(n, eg)
    #
    #
    # # param
    # # result Implementation rdfNodeFactory = new
    # def Implementation rdfNodeFactory = Implementation(self):
    #     # @Override
    # # param Node n, EnhGraph eg
    # # result boolean
    # def canWrap(self, n, eg):
    #         return True
    #
    #
    #     # @Override
    # # param Node n, EnhGraph eg
    # # result EnhNode
    # def wrap(self, n, eg):
    #         if (n.isURI() or n.isBlank()):
    #             return ResourceImpl(n, eg)
    #         if (n.isLiteral()):
    #             return LiteralImpl(n, eg)
    #         return None

    '''
     * the main constructor: make a Resource in the given model,
     * rooted in the given node.
     * <p>
     * NOT FOR PUBLIC USE - used in ModelCom [and ContainerImpl]
    '''

    def __init__(self):
        super().__init__(None, None)

    def initWithNodeAndModelCom(self, n, m):
        super().__init__(n, m)
        return self

    # param ModelCom m
    def initWithModelCom(self, m):
        self.initWithNodeAndModelCom(ResourceImpl.fresh(None), m)
        return self

    # param Node n, EnhGraph m
    def initWithNodeAndEnhGraph(self, n, m):
        self.initWithNodeAndModelCom(n, m)
        return self

    # param String uri
    def initWithUri(self, uri):
        self.initWithNodeAndModelCom(ResourceImpl.fresh(uri), None)
        return self

    # param String namespace, String localName
    def initWithNamespaceAndLocalName(self, namespace, localName):
        node = NodeFactory.createURI(namespace + localName)
        self.initWithNodeAndModelCom(node, None)
        return self

    # param AnonId id
    def initWithAnonId(self, id):
        self.initWithNodeAndModelCom(id, None)
        return self

    # param AnonId id, ModelCom m
    def initWithAnonIdAndModelCom(self, id, m):
        node = NodeFactory.createBlankNode(id.getLabelString())
        self.initWithNodeAndModelCom(node, m)
        return self

    # param String uri, ModelCom m
    def initWithUriAndModelCom(self, uri, m):
        self.initWithNodeAndModelCom(ResourceImpl.fresh(uri), m)
        return self

    # param Resource r, ModelCom m
    def initWithResourceAndModelCom(self, r, m):
        self.initWithNodeAndModelCom(r.asNode(), m)
        return self

    # param String nameSpace, String localName, ModelCom m
    def initWithNameSpaceAndLocalNameAndModelCom(self, nameSpace, localName, m):
        self.initWithNodeAndModelCom(NodeFactory.createURI(nameSpace + localName), m)
        return self

    # param Statement statement, ModelCom m
    def initWithStatementAndModelCom(self, statement, m):
        self.initWithNodeAndModelCom(NodeFactory.createTripleNode(statement.asTriple()), m)
        return self

    # @Override
    # param RDFVisitor rv
    # result Object
    # def visitWith(self, rv):
    #     if (self.isAnon()):
    #         return rv.visitBlank(self, self.getId())
    #     if (self.isStmtResource()):
    #         return rv.visitStmt(self, self.getStmtTerm())
    #     # if isURIResource()
    #     return rv.visitURI(self, self.getURI())

    # @Override
    # param 
    # result Resource
    def asResource(self):
        return self

    # @Override
    # param 
    # result Literal
    def asLiteral(self):
        raise LiteralRequiredException(self.asNode())

    # @Override
    # param Model m
    # result Resource
    def inModel(self, m):
        if (self.getModel() == m):
            return self
        if (self.isAnon()):
            return m.createResource(self.getId())
        if (self.isStmtResource()):
            return m.createResource(self.getStmtTerm())
        if (self.asNode().isConcrete() == False):
            # return (Resource) m.getRDFNode(self.asNode())
            return m.getRDFNode(self.asNode())
        # if isURIResource()
        return m.createResource(self.getURI())

    # param String uri
    # result static Node
    @staticmethod
    def fresh(uri):
        return NodeFactory.createBlankNode() if uri is None else NodeFactory.createURI(uri)

    # @Override
    # param 
    # result AnonId
    def getId(self):
        return AnonId(self.asNode().getBlankNodeId())

    # @Override
    # param 
    # result String
    def getURI(self):
        return self.node.getURI() if self.isURIResource() else None

    # @Override
    # param 
    # result Statement
    def getStmtTerm(self):
        if (not self.isStmtResource()):
            return None
        # Triple 
        t = self.node.getTriple()
        # Statement
        from base.rdf.impl.StatementImpl import StatementImpl
        stmt = StatementImpl.toStatement(t, self.getModelCom())
        return stmt

    # @Override
    # param 
    # result String
    def getNameSpace(self):
        if (not self.isURIResource()):
            return None
        return self.node.getNameSpace()

    # @Override
    # param 
    # result String
    def getLocalName(self):
        if (not self.isURIResource()):
            return None
        return self.node.getLocalName()

    # @Override
    # param String uri
    # result boolean
    def hasURI(self, uri):
        return self.node.hasURI(uri)

    # @Override
    # param 
    # result String
    def toString(self):
        return self.asNode().toString()

    # param 
    # result ModelCom
    def mustHaveModel(self):
        # ModelCom
        model = self.getModelCom()
        if (model is None):
            raise HasNoModelException(self)
        return model

    # @Override
    # param Property p
    # result Statement
    def getRequiredProperty(self, p):
        return self.mustHaveModel().getRequiredProperty(self, p)

    # @Override
    # param final Property p, final String lang
    # result Statement
    def getRequiredPropertyWithPropertyAndLang(self, p, lang):
        # final StmtIterator
        it = self.listPropertiesWithPropertyAndLang(p, lang)
        try:
            if (not it.hasNext()):
                raise PropertyNotFoundException(p)
            return it.next()
        finally:
            it.close()

    # @Override
    # param Property p
    # result Statement
    def getProperty(self, p):
        return self.mustHaveModel().getProperty(self, p)

    # @Override
    # param final Property p, final String lang
    # result Statement
    def getPropertyWithLang(self, p, lang):
        # final StmtIterator
        it = self.listPropertiesWithPropertyAndLang(p, lang)
        try:
            return it.hasNext() if it.next() else None
        finally:
            it.close()

    # @Override
    # param Property p
    # result StmtIterator
    def listPropertiesWithProperty(self, p):
        return self.mustHaveModel().listStatements(self, p, None)

    # @Override
    # param Property p, String lang
    # result StmtIterator
    def listPropertiesWithPropertyAndLang(self, p, lang):
        return self.mustHaveModel().listStatements(self, p, None, lang)

    # @Override
    # param 
    # result StmtIterator
    def listProperties(self):
        return self.mustHaveModel().listStatements(self, None, None)

    # @Override
    # param Property p, boolean o
    # result Resource
    def addLiteral(self, p, o):
        # ModelCom
        m = self.mustHaveModel()
        m.add(self, p, m.createTypedLiteral(o))
        return self

    # param Property p, long o
    # result Resource
    def addProperty(self, p, o):
        self.mustHaveModel().addLiteral(self, p, o)
        return self

    # @Override
    # param Property p, long o
    # result Resource
    # def addLiteral(self, p, o):
    #     Model m = self.mustHaveModel()
    #     m.add(self, p, m.createTypedLiteral(o))
    #     return self

    # @Override
    # param Property p, char o
    # result Resource
    # def addLiteral(self, p, o):
    #     ModelCom m = self.mustHaveModel()
    #     m.add(self, p, m.createTypedLiteral(o))
    #     return self

    # param Property p, float o
    # result Resource
    # def addProperty(self, p, o):
    #     self.mustHaveModel().addLiteral(self, p, o)
    #     return self

    # param Property p, double o
    # result Resource
    # def addProperty(self, p, o):
    #     self.mustHaveModel().addLiteral(self, p, o)
    #     return self
    #
    #
    # # @Override
    # # param Property p, double o
    # # result Resource
    # def addLiteral(self, p, o):
    #     Model m = self.mustHaveModel()
    #     m.add(self, p, m.createTypedLiteral(o))
    #     return self
    #
    #
    # # @Override
    # # param Property p, float o
    # # result Resource
    # def addLiteral(self, p, o):
    #     Model m = self.mustHaveModel()
    #     m.add(self, p, m.createTypedLiteral(o))
    #     return self
    #
    #
    # # @Override
    # # param Property p, String o
    # # result Resource
    # def addProperty(self, p, o):
    #     self.mustHaveModel().add(self, p, o)
    #     return self
    #
    #
    # # @Override
    # # param Property p, String o, String l
    # # result Resource
    # def addProperty(self, p, o, l):
    #     self.mustHaveModel().add(self, p, o, l)
    #     return self
    #
    #
    # # @Override
    # # param Property p, String lexicalForm, RDFDatatype datatype
    # # result Resource
    # def addProperty(self, p, lexicalForm, datatype):
    #     self.mustHaveModel().add(self, p, lexicalForm, datatype)
    #     return self
    #
    #
    # # @Override
    # # param Property p, Object o
    # # result Resource
    # def addLiteral(self, p, o):
    #     ModelCom m = self.mustHaveModel()
    #     m.add(self, p, m.createTypedLiteral(o))
    #     return self
    #
    #
    # # @Override
    # # param Property p, Literal o
    # # result Resource
    # def addLiteral(self, p, o):
    #     self.mustHaveModel().add(self, p, o)
    #     return self
    #
    #
    # # @Override
    # # param Property p, RDFNode o
    # # result Resource
    # def addProperty(self, p, o):
    #     self.mustHaveModel().add(self, p, o)
    #     return self

    # @Override
    # param Property p
    # result boolean
    def hasProperty(self, p):
        return self.mustHaveModel().contains(self, p)

    # @Override
    # param Property p, boolean o
    # result boolean
    def hasLiteral(self, p, o):
        # ModelCom
        m = self.mustHaveModel()
        return m.contains(self, p, m.createTypedLiteral(o))

    # @Override
    # param Property p, long o
    # result boolean
    # def hasLiteral(self, p, o):
    #     # ModelCom
    #     m = self.mustHaveModel()
    #     return m.contains(self, p, m.createTypedLiteral(o))
    #
    #
    # # @Override
    # # param Property p, char o
    # # result boolean
    # def hasLiteral(self, p, o):
    #     ModelCom m = self.mustHaveModel()
    #     return m.contains(self, p, m.createTypedLiteral(o))
    #
    #
    # # @Override
    # # param Property p, double o
    # # result boolean
    # def hasLiteral(self, p, o):
    #     ModelCom m = self.mustHaveModel()
    #     return m.contains(self, p, m.createTypedLiteral(o))
    #
    #
    # # @Override
    # # param Property p, float o
    # # result boolean
    # def hasLiteral(self, p, o):
    #     ModelCom m = self.mustHaveModel()
    #     return m.contains(self, p, m.createTypedLiteral(o))
    #
    #
    # # @Override
    # # param Property p, String o
    # # result boolean
    # def hasProperty(self, p, o):
    #     return self.mustHaveModel().contains(self, p, o)
    #
    #
    # # @Override
    # # param Property p, String o, String l
    # # result boolean
    # def hasProperty(self, p, o, l):
    #     return self.mustHaveModel().contains(self, p, o, l)
    #
    #
    # # @Override
    # # param Property p, Object o
    # # result boolean
    # def hasLiteral(self, p, o):
    #     ModelCom m = self.mustHaveModel()
    #     return m.contains(self, p, m.createTypedLiteral(o))
    #
    #
    # # @Override
    # # param Property p, RDFNode o
    # # result boolean
    # def hasProperty(self, p, o):
    #     return self.mustHaveModel().contains(self, p, o)

    # @Override
    # param 
    # result Resource
    def removeProperties(self):
        self.removeAll(None)
        return self

    # @Override
    # param Property p
    # result Resource
    def removeAll(self, p):
        self.mustHaveModel().removeAll(self, p, None)
        return self

    # @Override
    # param 
    # result Resource
    # def begin(self):
    #     self.mustHaveModel().begin()
    #     return self
    #
    # # @Override
    # # param
    # # result Resource
    # def abort(self):
    #     self.mustHaveModel().abort()
    #     return self
    #
    # # @Override
    # # param
    # # result Resource
    # def commit(self):
    #     self.mustHaveModel().commit()
    #     return self

    # @Override
    # param 
    # result Model
    def getModel(self):
        # return (Model) self.getGraph()
        return self.getGraph()

    # param 
    # result ModelCom
    def getModelCom(self):
        # return (ModelCom) self.getGraph()
        return self.getGraph()

    # @Override
    # param Property p
    # result Resource
    def getPropertyResourceValue(self, p):
        # StmtIterator
        it = self.listPropertiesWithProperty(p)
        try:
            while (it.hasNext()):
                # RDFNode
                n = it.next().getObject()
                if (n.isResource()):
                    return n
            return None
        finally:
            it.close()
